﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ClassLibrary1
{
    //泛型

    //一、泛型的概念
    //      允许我们延迟编写类或方法中的数据类型，直到真正使用时确定类型的一种规范
    //  1、为什么要使用泛型
    //     编写程序时经常遇到两个模块的功能非常相似，区别只是一个处理int数据,另一个处理string 数据，或者其他自定义的数据类型，我们只能分别编写多个方法处理不同的数据类型
    //     ,因为方法的参数类型不同
    //  2、针对1、的情况想到使用Object类型来解决这个问题，但这种方式有很大缺陷：
    //      （1）会出现装箱、折箱操作，这将在托管堆上分配和回收大量的变量，性能损失非常严重。
    //       （2）在处理引用类型时，虽然没有装箱和折箱操作，但将用到数据类型的强制转换操作，增加处理器的负担。

    //   泛型类型不是类型，而是类型的模板，就好比类型不是对象而是对象的模板一样。

    //   C#提供了五种泛型：类、结构、接口、委托和方法。前面四个是类型，而方法是成员。还是很迷吧，接下来对五种泛型分别进行讲解。

    //   使用泛型，本质上就是分别在  方法、类、委托、接口上再次抽象出来一层，实现了多态

    //声明泛型方法
    public class Fanxing
    {
        //定义泛型方法需要在方法名和参数列表之间加上<>,并在其中使用“T”来代表参数类型。
        //实际上T可以用任何有效名称来代替，也可以设置中文
        //泛型方法声明
        public static string TestMethod<T>(T a)
        {
            return a.GetType().ToString();
        }

        //调用泛型方法
        public void dosomething()
        {
            TestMethod<int>(10);
            TestMethod<string>("abc");
            TestMethod<float>(12.0f);
        }
    }


    //二、泛型类
    //泛型类的本质在于，给定不同的数据类型作为类的成员，在方法中进行相同的逻辑处理
    public class FanxingClass<T, C>//泛型类的字段参数类型列表
    {
        //泛型类的属性
        public T Age
        {
            get;
            set;
        }

        public C Cge
        {
            get; set;
        }

        //泛型类中的方法
        public string FanxingMethod(T a)
        {
            return a.GetType().ToString();
        }

        public string FanxingMethod1(T a, C b)
        {
            return a.GetType().ToString() + b.GetType().ToString();
        }
    }

    //使用泛型类
    public class useFanXingClass
    {
        public static void useFXClass()
        {
            //实例化泛型类时，要根据泛型类声明时规定的类型列表赋予实际使用的类型
            FanxingClass<int, int> fanxingClass = new FanxingClass<int, int>();
            //属性成员赋值
            fanxingClass.Age = 10;
            fanxingClass.Cge = 20;
            //调用方法成员
            fanxingClass.FanxingMethod(300);
            fanxingClass.FanxingMethod1(200, 300);

        }
    }

    /**
        三、泛型约束
            几个常见的泛型约束：
                1、where T : struct    约束 "T"的类型必须是结构
                2、where K : class     约束 "K"的类型必须是引用类型
                3、where V : IClass<T> 约束 "V"必须是继承自IClass<T>接口
                4、where W : className 约束 "W"约束 W 必须是 className 类型，或者是 className 类型的子类 
                5、where X : class, new()     约束 X 必须是引用类型，new()表示必须有一个无参数的构造函数，   当有多个约束时，new()必须写在最后  
    **/
    //泛型约束例子如下：
    //在泛型类中添加泛型约束
    class FanXingYueShu<T, K> where T : struct where K : class//各个泛型约束之间用空格隔开
    {
        public string FanXingYueShuMethod(T a)
        {
            return a.GetType().ToString();
        }

        public string FanXingYueShuMethod1(K b)
        {
            return b.GetType().ToString();
        }
    }

    public struct aa
    {
        public string a { get; set; }
        public string b { get; set; }
    }

    class DoSomething2
    {
        //调用泛型约束类的方法
        public DoSomething2()
        {
            FanXingYueShu<aa, string> fanXingYueShuClass = new FanXingYueShu<aa, string>();//实例化泛型约束类
            aa structAA = new aa();//创建aa类型的结构实例
            fanXingYueShuClass.FanXingYueShuMethod(structAA);//调用泛型约束类的方法
            fanXingYueShuClass.FanXingYueShuMethod1("aaaaa");//调用泛型约束类的方法
        }

    }




    /**
        五、泛型集合
            概念：
                泛型集合是泛型中最常见的应用，主要用于约束集合中存放的元素
            
            1、ArrayList 动态数组

                ArrayList的优点：
                        (1)、ArrayList的大小是按照其存储的数据动态的扩充和收缩的。
                        (2)、ArrayList在声明对象时并不需要指定其长度。
                        (3)、ArrayList可以很方便的进行数据的添加、插入和删除
                        (4)、ArrayList可以存储任意类型

                ArrayList的缺点
                        (1)、ArrayList在存储时是使用Object类型进行存储的
                        (2)、ArrayList不是类型安全的， 使用时很可能出现类型不匹配的错误，就算都插入了同一类型的数据，使用时我们也需要将其转化为对应的原类型来处理。
                        (3)、ArrayList存储和使用时存在拆箱和装箱的过程，导致其性能低下
            2、泛型集合：
                        List与数组比较类似，都用于存放一组值。List的元素长度不固定 数组必须固定
    **/
    //定义一个int类型的泛型集合
    public class FanXingList
    {
        //int类型的集合
        public void test()
        {
            List<int> IntList = new List<int>();
            //向集合中添加元素
            IntList.Add(1);
            //从集合中移除元素
            IntList.Remove(0);//0为元素角标
        }

        public void test1()
        {
            //创建泛型集合对象，指定其类型为People类型
            List<People> peoples = new List<People>();
            People people = new People();
            people.Age = 18;
            people.Height = 175;
            people.Name = "余冰";

            //向peoples泛型集合对象中添加people对象
            peoples.Add(people);

            //从peoples集合对象中移除元素
            peoples.Remove(people);
        }
    }
    public class People
    {
        public int Age { get; set; }
        public int Height { get; set; }
        public string Name { get; set; }
    }

}
